//
//  Router.swift
//  ECBase
//
//  Created by Tony on 2020/4/28.
//

import UIKit

final public class XYRouter: NSObject {
    static public let shared = XYRouter()
    private var viewControllers: [UINavigationController] = []
    fileprivate var needRequest: (AnyClass?, [String:Any], XYPresentType)?
    
    public var vc: UINavigationController? {
        get {
            return viewControllers.last
        }
    }
    
    private override init() {
        super.init()
    }
    
    public func setup(_ vc: UINavigationController) {
        self.viewControllers = [vc]
    }
    
    public func add(_ vc: UINavigationController) {
        self.viewControllers.append(vc)
    }
    public func remove() {
        if self.viewControllers.count > 1 {
            self.viewControllers.removeLast()
        }
    }
    public var getViewControllers: [UINavigationController] {
        viewControllers
    }
    public var visibleVC: UIViewController? {
        var targetVC = vc?.topViewController
        while targetVC?.presentedViewController != nil {
            targetVC = targetVC?.presentedViewController
        }
        return targetVC
    }
}

public extension NSObject {
    public func visibleVC() -> UIViewController? {
        return XYRouter.shared.visibleVC
    }
    public func handleVC(_ vc: AnyClass?, param:[String:Any] = [:], animation: Bool = true, type: XYPresentType = .push) {
        #if DEBUG
        assert(XYRouter.shared.vc != nil, "======== ERROR ===========\nRouter 类中没有给 viewController 赋值")
        #endif
        guard let root = XYRouter.shared.vc, let VC = root.visibleViewController else {return}
        // 开始跳转
        switch type {
        case .push: do {
            self.push(vc, param: param, animation: animation, type: type)
            break
            }
        case .pop: do {
            self.pop(vc, param: param, animation: animation, type: type)
            break
            }
        case .present: do {
            self.present(vc, param: param, animation: animation, type: type)
            break
            }
            case .presentWithNav: do {
            self.presentWithNav(vc, param: param, animation: animation, type: type)
            break
            }
        case .dismiss: do {
            self.dismiss(vc, param: param, animation: animation, type: type)
            break
            }
        case .popToRoot: do {
            self.popToRoot(vc, param: param, animation: animation, type: type)
            break
            }
        default:
            break
        }
    }
    
    private func push(_ vc: AnyClass?, param: [String:Any], animation: Bool, type: XYPresentType) {
        if let targetClass = vc as? UIViewController.Type, let viewController = XYRouter.shared.vc {
            if !self.checkLoginStatus(vc, param: param, type: type) {
                let target = targetClass.init()
                self.handleParam(target, param: param, type: type)
                viewController.pushViewController(target, animated: animation)
            }
        }
    }
    
    private func pop(_ vc: AnyClass?, param: [String:Any], animation: Bool, type: XYPresentType) {
        if let viewController = XYRouter.shared.vc, viewController.viewControllers.count > 1 {
            var target: UIViewController? = nil
            if let targetClass = vc as? UIViewController.Type {
                for i in 0 ..< viewController.viewControllers.count {
                    if viewController.viewControllers[i].classForCoder == targetClass {
                        target = viewController.viewControllers[i]
                    }
                }
            }
            if target == nil {
                target = viewController.viewControllers[viewController.viewControllers.count - 2]
                self.handleParam(target!, param: param, type: type)
            }
            if let target = target {
                viewController.popToViewController(target, animated: animation)
            }
        }
    }
    
    private func popToRoot(_ vc: AnyClass?, param: [String:Any], animation: Bool, type: XYPresentType) {
        while XYRouter.shared.getViewControllers.count > 1 {
            XYRouter.shared.getViewControllers.last?.dismiss(animated: false, completion: nil)
            XYRouter.shared.remove()
        }

        var visible: UIViewController? = XYRouter.shared.visibleVC
        while let vc = visible, let present = vc.presentingViewController {
            vc.dismiss(animated: false, completion: nil)
            visible = present
        }

        if let viewController = XYRouter.shared.vc, let target = viewController.viewControllers.first {
            self.handleParam(target, param: param, type: type)
            viewController.popToRootViewController(animated: animation)
        }
    }
    
    private func present(_ vc: AnyClass?, param: [String:Any], animation: Bool, type: XYPresentType) {
        if let targetClass = vc as? UIViewController.Type, let viewController = XYRouter.shared.visibleVC {
            if !self.checkLoginStatus(vc, param: param, type: type) {
                let target = targetClass.init()
                self.handleParam(target, param: param, type: type)
                if let nav = target as? UINavigationController {
                    XYRouter.shared.add(nav)
                }
                viewController.present(target, animated: animation, completion: nil)
            }
        }
    }
    
    private func presentWithNav(_ vc: AnyClass?, param: [String:Any], animation: Bool, type: XYPresentType) {
        if let targetClass = vc as? UIViewController.Type, let viewController = XYRouter.shared.visibleVC {
            if !self.checkLoginStatus(vc, param: param, type: type) {
                var target: XYNavigationController
                let rootVC = targetClass.init()
                if let vc = rootVC as? XYNavigationController {
                    target = vc
                } else {
                    target = XYNavigationController(rootViewController: rootVC)
                }
                self.handleParam(rootVC, param: param, type: type)
                XYRouter.shared.add(target)
                target.modalPresentationStyle = .fullScreen
                viewController.present(target, animated: animation, completion: nil)
            }
        }
    }
    
    private func dismiss(_ vc: AnyClass?, param: [String:Any], animation: Bool, type: XYPresentType) {
        if var viewController = XYRouter.shared.visibleVC, viewController.presentingViewController != nil {
            if viewController.navigationController != nil {
                XYRouter.shared.remove()
            }
            
            var targetVC: UIViewController? = viewController.presentingViewController
            while targetVC != nil, targetVC!.isBeingDismissed, targetVC!.presentingViewController != nil {
                viewController = targetVC!
                targetVC = targetVC!.presentingViewController
            }
            if let nav = targetVC as? UINavigationController {
                targetVC = nav.topViewController
            }
            self.handleParam(targetVC!, param: param, type: type)
            viewController.dismiss(animated: animation, completion: nil)
        }
    
    }
    
    private func checkLoginStatus(_ vc: AnyClass?, param: [String:Any], type: XYPresentType) -> Bool {
        if let current = vc as? XYBaseViewControllerProtocol, current.needLogin() {
            self.startLogin(vc, param: param, type: type)
            return true
        }
        return false
    }
    
    public func startLogin(_ vc: AnyClass?, param:[String:Any] = [:], type: XYPresentType) {
        XYRouter.shared.needRequest = (vc, param, type)
        //TODO: 跳转到登录, 第一个版本没有登录
    }
    
    private func handleParam(_ vc: UIViewController, param:[String:Any], type: XYPresentType) {
        if let target = vc as? XYBaseViewControllerProtocol {
            target.didReceiveParam(param, presentType: type)
        }
        
    }
}
